#include "common/map_utility.h"

#include <fstream>
#include <iostream>
#include <limits>

#include "common/map_utility_impl.h"

namespace boost::json {
autodrive::perception::MapElementPoint tag_invoke(
    boost::json::value_to_tag<autodrive::perception::MapElementPoint>,
    boost::json::value const& jv) {
  std::uint8_t const& xyzFeatureNum{3};
  std::uint8_t const& withScoreFeatureNum{4};
  autodrive::perception::MapElementPoint mapPoint{0};

  auto const& point{boost::json::value_to<JPoint>(jv)};

  if (point.size() >= xyzFeatureNum) {
    mapPoint.x = autodrive::perception::clip<float>(point.at(0));
    mapPoint.y = autodrive::perception::clip<float>(point.at(1));
    mapPoint.z = autodrive::perception::clip<float>(point.at(2));
  }

  if (point.size() >= withScoreFeatureNum) {
    mapPoint.score = point.at(3);

    for (std::uint32_t i{withScoreFeatureNum}; i < point.size(); ++i) {
      std::uint32_t const& index{i - withScoreFeatureNum};
      std::uint32_t rSize{
          sizeof(autodrive::perception::MapElementPoint::reserve) /
          sizeof(autodrive::perception::MapElementPoint::type)};
      if (index > 0 && index < rSize) {
        mapPoint.reserve[index] =
            autodrive::perception::clip<float>(point.at(i));
      }
    }
  }

  return mapPoint;
}

autodrive::perception::MapElementPointSet tag_invoke(
    boost::json::value_to_tag<autodrive::perception::MapElementPointSet>,
    boost::json::value const& jv) {
  auto const& points{
      boost::json::value_to<std::list<autodrive::perception::MapElementPoint>>(
          jv)};
  autodrive::perception::MapElementPointSet pointSet;
  pointSet.clear();
  memset(&pointSet, 0, sizeof(autodrive::perception::MapElementPointSet));

  for (auto const& p : points) {
    pointSet.add(p);
  }
  return pointSet;
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::MapElementPoint const& point) {
  boost::json::array jPoint;
  std::int32_t rSize{sizeof(autodrive::perception::MapElementPoint::reserve) /
                     sizeof(autodrive::perception::MapElementPoint::type)};
  jPoint.emplace_back(point.x);
  jPoint.emplace_back(point.y);
  jPoint.emplace_back(point.z);
  jPoint.emplace_back(point.score);
  for (std::int32_t j{0}; j < rSize; ++j) {
    jPoint.emplace_back(point.reserve[j]);
  }
  jv = jPoint;
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::MapElementPointSet const& pointSet) {
  boost::json::array jPointSet;
  jPointSet.clear();
  std::int32_t rSize{sizeof(autodrive::perception::MapElementPoint::reserve) /
                     sizeof(autodrive::perception::MapElementPoint::type)};
  for (std::uint32_t i{0}; i < pointSet.size(); ++i) {
    auto const& p{pointSet.at(i)};
    jPointSet.emplace_back(boost::json::value_from(p));
  }
  jv = jPointSet;
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::RoadEdge const& roadEdge) {
  std::string category{""};
  switch (roadEdge.category) {
    case autodrive::perception::RoadEdgeCategory::ROAD_EDGE:
      category = "road_edge";
      break;
    case autodrive::perception::RoadEdgeCategory::TRAFFIC_BARRIER:
      category = "traffic_barrier";
      break;
    default:
      category = "unknown";
      break;
  }

  jv = {{sIDProperty, value_from(std::string(roadEdge.id))},
        {sCategoryProperty, value_from(category)},
        {sPointsProperty, value_from(roadEdge.points)}};
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::LaneDivider const& lanedivider) {
  std::string lineType{""};
  std::string color{""};

  switch (lanedivider.line_type) {
    case autodrive::perception::LaneDividerLineType::DASHED:
      lineType = "dashed";
      break;
    case autodrive::perception::LaneDividerLineType::SOLID:
      lineType = "solid";
      break;
    default:
      lineType = "unknown";
      break;
  }

  switch (lanedivider.color) {
    case autodrive::perception::LaneDividerColor::BLUE:
      color = "blue";
      break;
    case autodrive::perception::LaneDividerColor::GREEN:
      color = "green";
      break;
    case autodrive::perception::LaneDividerColor::RED:
      color = "red";
      break;
    case autodrive::perception::LaneDividerColor::WHITE:
      color = "white";
      break;
    case autodrive::perception::LaneDividerColor::YELLOW:
      color = "yellow";
      break;
    default:
      color = "unknown";
      break;
  }

  jv = {{sIDProperty, value_from(std::string(lanedivider.id))},
        {sLineTypeProperty, value_from(lineType)},
        {sColorProperty, value_from(color)},
        {sPointsProperty, value_from(lanedivider.points)}};
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::CenterLine const& centerLine) {
  std::list<std::string> ids;
  for (std::uint32_t i{0}; i < centerLine.topo_point_ids.size(); ++i) {
    ids.emplace_back(std::string(centerLine.topo_point_ids.at(i)));
  }

  jv = {{sIDProperty, value_from(std::string(centerLine.id))},
        {sCenterLineTopoIDsProperty, value_from(ids)},
        {sPointsProperty, value_from(centerLine.points)}};
}

void tag_invoke(
    boost::json::value_from_tag, boost::json::value& jv,
    autodrive::perception::LaneDividerJoint const& lanedividerJoint) {
  jv = {{sID1Property,
         value_from(std::string(lanedividerJoint.lane_divider_id1))},
        {sID2Property,
         value_from(std::string(lanedividerJoint.lane_divider_id2))},
        {sPointProperty, value_from(lanedividerJoint.point)}};
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::RoadMarking const& roadMarking) {
  std::list<std::string> catagoryList;
  std::vector<float> center{roadMarking.center.x, roadMarking.center.y,
                            roadMarking.center.z};
  for (std::int32_t i{0}; i < roadMarking.category.size(); ++i) {
    auto const& catagoryItem{roadMarking.category.at(i)};
    switch (catagoryItem) {
      case autodrive::perception::RoadMarkingCategory::UNKNOWN:
        catagoryList.emplace_back("unknown");
        break;
      case autodrive::perception::RoadMarkingCategory::STRAIGHT:
        catagoryList.emplace_back("straight");
        break;
      case autodrive::perception::RoadMarkingCategory::LEFT:
        catagoryList.emplace_back("left");
        break;
      case autodrive::perception::RoadMarkingCategory::RIGHT:
        catagoryList.emplace_back("right");
        break;
      case autodrive::perception::RoadMarkingCategory::U_TURN:
        catagoryList.emplace_back("u_turn");
        break;
      case autodrive::perception::RoadMarkingCategory::CROSS:
        catagoryList.emplace_back("cross");
        break;
      case autodrive::perception::RoadMarkingCategory::NO_STOP:
        catagoryList.emplace_back("no_stop");
        break;
      case autodrive::perception::RoadMarkingCategory::CROSSWALK:
        catagoryList.emplace_back("crosswalk");
        break;
      case autodrive::perception::RoadMarkingCategory::STOP_LINE:
        catagoryList.emplace_back("stop_line");
        break;
      case autodrive::perception::RoadMarkingCategory::SPEED_BUMP:
        catagoryList.emplace_back("speed_bump");
        break;
      case autodrive::perception::RoadMarkingCategory::CONFLUENCE_LEFT:
        catagoryList.emplace_back("confluence_left");
        break;
      case autodrive::perception::RoadMarkingCategory::CONFLUENCE_RIGHT:
        catagoryList.emplace_back("confluence_right");
        break;
      default:
        catagoryList.emplace_back("unknown");
        break;
    }
  }

  jv = {{sIDProperty, value_from(string(roadMarking.id))},
        {sCategoryProperty, value_from(catagoryList)},
        {sCenterProperty, value_from(center)},
        {sLengthProperty, roadMarking.length},
        {sWidthProperty, roadMarking.width},
        {sHeightProperty, roadMarking.height},
        {sYawProperty, roadMarking.yaw},
        {sPolygonProperty, value_from(roadMarking.points)}};
}

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
                autodrive::perception::Map const& map) {
  std::list<autodrive::perception::RoadEdge> roadEdges;
  std::list<autodrive::perception::LaneDivider> laneDividers;
  std::list<autodrive::perception::CenterLine> centerLines;
  std::list<autodrive::perception::LaneDividerJoint> laneDividerJoints;
  std::list<autodrive::perception::RoadMarking> roadMarking;

  for (std::uint32_t i{0}; i < map.road_edge.size(); ++i) {
    roadEdges.emplace_back(map.road_edge.at(i));
  }

  for (std::uint32_t i{0}; i < map.lane_divider.size(); ++i) {
    laneDividers.emplace_back(map.lane_divider.at(i));
  }

  for (std::uint32_t i{0}; i < map.center_line.size(); ++i) {
    centerLines.emplace_back(map.center_line.at(i));
  }

  for (std::uint32_t i{0}; i < map.lane_divider_joint.size(); ++i) {
    laneDividerJoints.emplace_back(map.lane_divider_joint.at(i));
  }

  for (std::uint32_t i{0}; i < map.road_marking.size(); ++i) {
    roadMarking.emplace_back(map.road_marking.at(i));
  }

  jv = {{sRoadEdgeProperty, value_from(roadEdges)},
        {sLaneDividerProperty, value_from(laneDividers)},
        {sCenterLineProperty, value_from(centerLines)},
        {sLaneDividerJointProperty, value_from(laneDividerJoints)},
        {sRoadMarkingProperty, value_from(roadMarking)}};
}
}  // namespace boost::json

namespace autodrive {
namespace perception {
void parse_road_edge(boost::json::value const& jv,
                     RoadEdge& roadEdge) noexcept {
  std::string category{""};

  auto const& obj{jv.as_object()};

  memset(roadEdge.id, '\0', KMaxIDLength);

  roadEdge.category = autodrive::perception::RoadEdgeCategory::UNKNOWN;
  memset(&roadEdge.points, 0,
         sizeof(autodrive::perception::MapElementPointSet));

  if (obj.contains(boost::json::sIDProperty)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sIDProperty))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(roadEdge.id, id.c_str(), length);
  }

  if (obj.contains(boost::json::sCategoryProperty)) {
    category = boost::json::value_to<std::string>(
        obj.at(boost::json::sCategoryProperty));
  }

  if (obj.contains(boost::json::sPointsProperty)) {
    roadEdge.points =
        boost::json::value_to<autodrive::perception::MapElementPointSet>(
            obj.at(boost::json::sPointsProperty));
  }

  if (category.compare("road_edge") == 0) {
    roadEdge.category = autodrive::perception::RoadEdgeCategory::ROAD_EDGE;
  } else if (category.compare("traffic_barrier") == 0) {
    roadEdge.category =
        autodrive::perception::RoadEdgeCategory::TRAFFIC_BARRIER;
  } else {
    roadEdge.category = autodrive::perception::RoadEdgeCategory::UNKNOWN;
  }
}

void parse_lane_divider(boost::json::value const& jv,
                        LaneDivider& laneDivider) noexcept {
  std::string lineType{""};
  std::string color{""};

  auto const& obj{jv.as_object()};

  memset(laneDivider.id, '\0', KMaxIDLength);
  laneDivider.line_type = autodrive::perception::LaneDividerLineType::UNKNOWN;
  laneDivider.color = autodrive::perception::LaneDividerColor::UNKNOWN;
  memset(&laneDivider.points, 0,
         sizeof(autodrive::perception::MapElementPointSet));

  if (obj.contains(boost::json::sIDProperty)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sIDProperty))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(laneDivider.id, id.c_str(), length);
  }

  if (obj.contains(boost::json::sLineTypeProperty)) {
    lineType = boost::json::value_to<std::string>(
        obj.at(boost::json::sLineTypeProperty));
  }

  if (obj.contains(boost::json::sColorProperty)) {
    color =
        boost::json::value_to<std::string>(obj.at(boost::json::sColorProperty));
  }

  if (obj.contains(boost::json::sPointsProperty)) {
    laneDivider.points =
        boost::json::value_to<autodrive::perception::MapElementPointSet>(
            obj.at(boost::json::sPointsProperty));
  }

  if (lineType == "solid") {
    laneDivider.line_type = autodrive::perception::LaneDividerLineType::SOLID;
  } else if (lineType == "dashed") {
    laneDivider.line_type = autodrive::perception::LaneDividerLineType::DASHED;
  } else {
    laneDivider.line_type = autodrive::perception::LaneDividerLineType::UNKNOWN;
  }

  if (color.compare("white") == 0) {
    laneDivider.color = autodrive::perception::LaneDividerColor::WHITE;
  } else if (color.compare("yellow") == 0) {
    laneDivider.color = autodrive::perception::LaneDividerColor::YELLOW;
  } else if (color.compare("blue") == 0) {
    laneDivider.color = autodrive::perception::LaneDividerColor::BLUE;
  } else if (color.compare("green") == 0) {
    laneDivider.color = autodrive::perception::LaneDividerColor::GREEN;
  } else if (color.compare("red") == 0) {
    laneDivider.color = autodrive::perception::LaneDividerColor::RED;
  } else {
    laneDivider.color = autodrive::perception::LaneDividerColor::UNKNOWN;
  }
}

void parse_center_line(boost::json::value const& jv,
                       CenterLine& centerLine) noexcept {
  std::string category{""};

  auto const& obj{jv.as_object()};

  memset(centerLine.id, '\0', KMaxIDLength);
  centerLine.topo_point_ids.clear();
  memset(&centerLine.points, 0,
         sizeof(autodrive::perception::MapElementPointSet));

  if (obj.contains(boost::json::sIDProperty)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sIDProperty))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(centerLine.id, id.c_str(), length);
  }

  if (obj.contains(boost::json::sCenterLineTopoIDsProperty)) {
    auto const& topoIDs{boost::json::value_to<std::list<std::string>>(
        obj.at(boost::json::sCenterLineTopoIDsProperty))};
    centerLine.topo_point_ids.clear();
    for (auto const& id : topoIDs) {
      if (centerLine.topo_point_ids.full()) {
        break;
      }
      centerLine.topo_point_ids.resize(centerLine.topo_point_ids.size() + 1);
      auto index{centerLine.topo_point_ids.size() - 1};
      strcpy(centerLine.topo_point_ids.at(index), id.c_str());
    }
  }

  if (obj.contains(boost::json::sPointsProperty)) {
    centerLine.points =
        boost::json::value_to<autodrive::perception::MapElementPointSet>(
            obj.at(boost::json::sPointsProperty));
  }
}

void parse_lane_divider_joint(boost::json::value const& jv,
                              LaneDividerJoint& laneDividerJoint) noexcept {
  auto const& obj{jv.as_object()};

  memset(laneDividerJoint.lane_divider_id1, '\0', KMaxIDLength);
  memset(laneDividerJoint.lane_divider_id2, '\0', KMaxIDLength);

  memset(&laneDividerJoint.point, 0,
         sizeof(autodrive::perception::MapElementPoint));

  if (obj.contains(boost::json::sID1Property)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sID1Property))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(laneDividerJoint.lane_divider_id1, id.c_str(), length);
  }

  if (obj.contains(boost::json::sID2Property)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sID2Property))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(laneDividerJoint.lane_divider_id2, id.c_str(), length);
  }

  if (obj.contains(boost::json::sPointProperty)) {
    laneDividerJoint.point =
        boost::json::value_to<autodrive::perception::MapElementPoint>(
            obj.at(boost::json::sPointProperty));
  }
}

void parse_road_marking(boost::json::value const& jv,
                        RoadMarking& roadMarking) noexcept {
  std::list<std::string> catagoryList;

  auto const& obj{jv.as_object()};

  memset(roadMarking.id, '\0', KMaxIDLength);
  roadMarking.category.clear();
  roadMarking.length = 0;
  roadMarking.width = 0;
  roadMarking.height = 0;
  roadMarking.center = {0};
  roadMarking.yaw = 0;
  memset(&roadMarking.points, 0,
         sizeof(autodrive::perception::MapElementPointSet));

  if (obj.contains(boost::json::sIDProperty)) {
    auto const& id{
        boost::json::value_to<std::string>(obj.at(boost::json::sIDProperty))};
    auto length{
        std::min(KMaxIDLength, static_cast<std::uint32_t>(id.length()))};
    strncpy(roadMarking.id, id.c_str(), length);
  }

  if (obj.contains(boost::json::sCategoryProperty)) {
    auto const& catagoryList{boost::json::value_to<std::list<std::string>>(
        obj.at(boost::json::sCategoryProperty))};
    roadMarking.category.clear();
    for (auto const& c : catagoryList) {
      autodrive::perception::RoadMarkingCategory rCatagory;
      if (c.compare("straight") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::STRAIGHT;
      } else if (c.compare("left") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::LEFT;
      } else if (c.compare("right") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::RIGHT;
      } else if (c.compare("u_turn") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::U_TURN;
      } else if (c.compare("cross") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::CROSS;
      } else if (c.compare("no_stop") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::NO_STOP;
      } else if (c.compare("crosswalk") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::CROSSWALK;
      } else if (c.compare("stop_line") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::STOP_LINE;
      } else if (c.compare("speed_bump") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::SPEED_BUMP;
      } else if (c.compare("confluence_left") == 0) {
        rCatagory = autodrive::perception::RoadMarkingCategory::CONFLUENCE_LEFT;
      } else if (c.compare("confluence_right") == 0) {
        rCatagory =
            autodrive::perception::RoadMarkingCategory::CONFLUENCE_RIGHT;
      } else {
        rCatagory = autodrive::perception::RoadMarkingCategory::UNKNOWN;
      }
      roadMarking.category.add(rCatagory);
    }
  }

  std::uint8_t const& xyzFeatureNum{3};
  if (obj.contains(boost::json::sCenterProperty)) {
    auto const& jPoint{boost::json::value_to<boost::json::JPoint>(
        obj.at(boost::json::sCenterProperty))};
    if (jPoint.size() >= xyzFeatureNum) {
      roadMarking.center = {autodrive::perception::clip<float>(jPoint.at(0)),
                            autodrive::perception::clip<float>(jPoint.at(1)),
                            autodrive::perception::clip<float>(jPoint.at(2))};
    }
  }

  if (obj.contains(boost::json::sLengthProperty)) {
    roadMarking.length =
        boost::json::value_to<float>(obj.at(boost::json::sLengthProperty));
  }

  if (obj.contains(boost::json::sWidthProperty)) {
    roadMarking.width =
        boost::json::value_to<float>(obj.at(boost::json::sWidthProperty));
  }

  if (obj.contains(boost::json::sHeightProperty)) {
    roadMarking.height =
        boost::json::value_to<float>(obj.at(boost::json::sHeightProperty));
  }

  if (obj.contains(boost::json::sYawProperty)) {
    roadMarking.yaw =
        boost::json::value_to<float>(obj.at(boost::json::sYawProperty));
  }

  if (obj.contains(boost::json::sPolygonProperty)) {
    roadMarking.points =
        boost::json::value_to<autodrive::perception::MapElementPointSet>(
            obj.at(boost::json::sPolygonProperty));
  }
}

void read_map_json(std::filesystem::path const& file_path,
                   Map& map) noexcept(false) {
  if (!std::filesystem::exists(file_path)) {
    throw std::runtime_error("file " + file_path.string() + " does not exist");
  }

  std::ifstream stream{file_path};
  std::stringstream s;
  s << stream.rdbuf();

  boost::json::value jv;

  try {
    boost::json::error_code ec;
    jv = boost::json::parse(s.str(), ec);
    if (ec.value() != 0) {
      throw std::runtime_error("parse json string fail: " + ec.message());
    }
  } catch (const std::exception& e) {
    throw std::runtime_error("parse json string fail: " +
                             std::string(e.what()));
  }

  auto const& joRoot{jv.as_object()};

  // road edge
  if (joRoot.contains(boost::json::sRoadEdgeProperty)) {
    auto const& jvRoadEdges{joRoot.at(boost::json::sRoadEdgeProperty)};
    if (jvRoadEdges.is_array()) {
      map.road_edge.clear();
      for (auto const& jvRoadEdge : jvRoadEdges.as_array()) {
        if (map.road_edge.full()) {
          break;
        }
        auto roadEdge{map.road_edge.end()};
        parse_road_edge(jvRoadEdge, *roadEdge);
        map.road_edge.resize(map.road_edge.size() + 1);
      }
    }
  }

  // // lane divider
  if (joRoot.contains(boost::json::sLaneDividerProperty)) {
    auto const& jvLaneDividers{joRoot.at(boost::json::sLaneDividerProperty)};
    if (jvLaneDividers.is_array()) {
      map.lane_divider.clear();
      for (auto const& jvLaneDivider : jvLaneDividers.as_array()) {
        if (map.lane_divider.full()) {
          break;
        }
        auto laneDivider{map.lane_divider.end()};
        parse_lane_divider(jvLaneDivider, *laneDivider);
        map.lane_divider.resize(map.lane_divider.size() + 1);
      }
    }
  }

  // center line
  if (joRoot.contains(boost::json::sCenterLineProperty)) {
    auto const& jvCenterLines{joRoot.at(boost::json::sCenterLineProperty)};
    if (jvCenterLines.is_array()) {
      map.center_line.clear();
      for (auto const& jvCenterLine : jvCenterLines.as_array()) {
        if (map.center_line.full()) {
          break;
        }
        auto centerLine{map.center_line.end()};
        parse_center_line(jvCenterLine, *centerLine);
        map.center_line.resize(map.center_line.size() + 1);
      }
    }
  }

  // lane divider joint
  if (joRoot.contains(boost::json::sLaneDividerJointProperty)) {
    auto const& jvLaneDividerJoints{
        joRoot.at(boost::json::sLaneDividerJointProperty)};
    if (jvLaneDividerJoints.is_array()) {
      map.lane_divider_joint.clear();
      for (auto const& jvLaneDividerJoint : jvLaneDividerJoints.as_array()) {
        if (map.lane_divider_joint.full()) {
          break;
        }
        auto laneDividerJoint{map.lane_divider_joint.end()};
        parse_lane_divider_joint(jvLaneDividerJoint, *laneDividerJoint);
        map.lane_divider_joint.resize(map.lane_divider_joint.size() + 1);
      }
    }
  }

  // road marking
  if (joRoot.contains(boost::json::sRoadMarkingProperty)) {
    auto const& jvRoadMarkings{joRoot.at(boost::json::sRoadMarkingProperty)};
    if (jvRoadMarkings.is_array()) {
      map.road_marking.clear();
      for (auto const& jvRoadMarking : jvRoadMarkings.as_array()) {
        if (map.road_marking.full()) {
          break;
        }
        auto roadMarking{map.road_marking.end()};
        parse_road_marking(jvRoadMarking, *roadMarking);
        map.road_marking.resize(map.road_marking.size() + 1);
      }
    }
  }
}

void write_map_json(Map const& map,
                    std::filesystem::path const& file_path) noexcept(false) {
  try {
    auto const& jvMap{boost::json::value_from(map)};
    auto const& strJvMap{boost::json::serialize(jvMap)};
    std::ofstream stream{file_path};
    stream << strJvMap;
  } catch (const std::exception& e) {
    throw std::runtime_error("write map to json error, " +
                             std::string(e.what()));
  } catch (...) {
    throw std::runtime_error("write map to json unexpeced error");
  }
}
}  // namespace perception
}  // namespace autodrive
